﻿#include "PostMarkerInteractionStyle.h"

#include <QAction>
#include <QCoreApplication>
#include <QDebug>
#include <QKeyEvent>
#include <QList>
#include <QMenu>

#include <vtkActor.h>
#include <vtkAreaPicker.h>
#include <vtkAxesActor.h>
#include <vtkCamera.h>
#include <vtkCell.h>
#include <vtkCellPicker.h>
#include <vtkCoordinate.h>
#include <vtkDataSet.h>
#include <vtkDataSet.h>
#include <vtkDataSetMapper.h>
#include <vtkDistanceToCamera.h>
#include <vtkExtractGeometry.h>
#include <vtkExtractSelection.h>
#include <vtkGlyph3D.h>
#include <vtkMapper.h>
#include <vtkNamedColors.h>
#include <vtkPlanes.h>
#include <vtkPointPicker.h>
#include <vtkPolyData.h>
#include <vtkPolyDataMapper.h>
#include <vtkProperty.h>
#include <vtkPropPicker.h>
#include <vtkRenderer.h>
#include <vtkRendererCollection.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkSelection.h>
#include <vtkSelectionNode.h>
#include <vtkSmartPointer.h>
#include <vtkSphereSource.h>
#include <vtkTransform.h>
#include <vtkExtractCells.h>
#include <vtkGeometryFilter.h>
#include <vtkFeatureEdges.h>
#include <vtkCellData.h>
#include <Graph3DWindowBase.h>
#include <vtkPointData.h>

#include "DataManager/WindowTotalData.h"
#include "BaseModule/IBaseSignal.h"

namespace pst
{
    vtkStandardNewMacro(PostMarkerInteractionStyle);

    PostMarkerInteractionStyle::PostMarkerInteractionStyle()
        : m_cellPicker(vtkSmartPointer<vtkCellPicker>::New())
        , m_pointPicker(vtkSmartPointer<vtkCellPicker>::New())
        //, m_postWindow(nullptr)
        , m_isEnablePicking(false)
        , m_namedColor(vtkSmartPointer<vtkNamedColors>::New())
        , m_moveMapper(vtkSmartPointer<vtkPolyDataMapper>::New())
        , m_moveActor(vtkSmartPointer<vtkActor>::New())
        , m_distanceToCamera(vtkSmartPointer<vtkDistanceToCamera>::New())
        , m_pickerType(0), extractCells(vtkSmartPointer<vtkExtractCells>::New())
        , geometryFilter(vtkSmartPointer<vtkGeometryFilter>::New())
        , featureEdges(vtkSmartPointer<vtkFeatureEdges>::New())
        , edgeMapper(vtkSmartPointer<vtkDataSetMapper>::New())
        , edgeActor(vtkSmartPointer<vtkActor>::New())
        , idList(vtkSmartPointer<vtkIdList>::New())
        , m_graph3DWindowBase(nullptr)
        , m_interactionStyle(0)
    {
        generateFixedSizeBall();
        initCellPickerPipeLine();
        m_pointPicker->SetTolerance(0.005);
        m_cellPicker->SetTolerance(0.005);
    }

    PostMarkerInteractionStyle::~PostMarkerInteractionStyle()
    {
    }

    void PostMarkerInteractionStyle::generateFixedSizeBall()
    {
        vtkNew<vtkPointSource> fixedPointSource;
        fixedPointSource->SetCenter(0, 0, 0);
        fixedPointSource->SetRadius(0.000001);
        fixedPointSource->SetNumberOfPoints(1);

        m_distanceToCamera->SetInputConnection(fixedPointSource->GetOutputPort());
        m_distanceToCamera->SetScreenSize(35);

        vtkNew<vtkSphereSource> shpere;
        vtkNew<vtkGlyph3D> fixedGlyph;
        fixedGlyph->SetInputConnection(m_distanceToCamera->GetOutputPort());
        fixedGlyph->SetSourceConnection(shpere->GetOutputPort());
        fixedGlyph->SetScaleModeToScaleByScalar();
        fixedGlyph->SetInputArrayToProcess(
            0, 0, 0, vtkDataObject::FIELD_ASSOCIATION_POINTS, "DistanceToCamera");

        m_moveMapper->SetInputConnection(fixedGlyph->GetOutputPort());
        m_moveMapper->SetScalarVisibility(false);

        m_moveActor->SetMapper(m_moveMapper);
        vtkNew<vtkNamedColors> colors;
        edgeActor->GetProperty()->SetColor(0.0, 1.0, 0.0);
        m_moveActor->SetPickable(false);
        m_moveActor->SetVisibility(false);
        m_distanceToCamera->SetRenderer(this->GetDefaultRenderer());
    }

    void PostMarkerInteractionStyle::initCellPickerPipeLine()
    {
        //extractCells->SetInputData(dataSet);
        extractCells->SetCellList(idList);
        geometryFilter->SetInputConnection(extractCells->GetOutputPort());
        featureEdges->SetInputConnection(geometryFilter->GetOutputPort());
        featureEdges->BoundaryEdgesOn(); // 只保留边界边
        featureEdges->FeatureEdgesOn();
        featureEdges->NonManifoldEdgesOn();
        featureEdges->ManifoldEdgesOn();
        edgeMapper->SetInputConnection(featureEdges->GetOutputPort());
        edgeActor->SetMapper(edgeMapper);
        edgeActor->GetProperty()->SetColor(0.0, 1.0, 0.0);
        edgeActor->GetProperty()->SetLineWidth(3.0);
        edgeActor->SetPickable(false);
        //m_renderer3D->AddActor(edgeActor);
        //extractCells->Update();
    }

    // void PostMarkerInteractionStyle::setPostWindow(PostWindowBase* win)
    //{
    //     m_postWindow = win;
    // }

    void PostMarkerInteractionStyle::setPickerType(int type)
    {
        m_pickerType = type;
        m_moveActor->SetVisibility(false);
        edgeActor->SetVisibility(false);
    }

    int PostMarkerInteractionStyle::getPickerType() const
    {
        return m_pickerType;
    }

    void PostMarkerInteractionStyle::setMoveSphereRadius(int radius)
    {
        m_distanceToCamera->SetScreenSize(radius);
        m_distanceToCamera->Modified();
        this->GetCurrentRenderer()->GetRenderWindow()->Render();
    }

    void PostMarkerInteractionStyle::setEnablePicking(bool on)
    {
        m_isEnablePicking = on;
        if (!on)
        {
            m_moveActor->SetVisibility(false);
            edgeActor->SetVisibility(false);
        }
    }

    void PostMarkerInteractionStyle::setRender(vtkRenderer* render)
    {
        render->AddActor(m_moveActor);
        m_distanceToCamera->SetRenderer(render);
        this->SetDefaultRenderer(render);
    }

    void PostMarkerInteractionStyle::setParentWindow(Graph3DWindowBase* win)
    {
        m_graph3DWindowBase = win;
    }

    void PostMarkerInteractionStyle::setInnerInteractionStyle(int style)
    {
        m_interactionStyle = style;
    }

    int PostMarkerInteractionStyle::getInnerInteractionStyle() const
    {
        return m_interactionStyle;
    }

    void PostMarkerInteractionStyle::OnLeftButtonDown()
    {
        if (m_interactionStyle == 0) // 左键按住是旋转
        {
            vtkInteractorStyleTrackballCamera::OnLeftButtonDown();
        }
        else if (m_interactionStyle == 1) // 左键按住是平移
        {
            vtkInteractorStyleTrackballCamera::OnMiddleButtonDown();
        }
        if (!m_isEnablePicking)
        {
            return;
        }

        int* clickPos = this->GetInteractor()->GetEventPosition();

        if (m_pickerType == 0) // 点拾取
        {
            int success = -1;
            success = m_pointPicker->Pick(clickPos[0], clickPos[1], 0, this->GetDefaultRenderer());
            auto actor = m_pointPicker->GetActor();
            int infomationGraph3DBasicalId = WindowTotalDataInstance->getInfomationGraph3DBasicalIdByActor(actor);
            auto currentPointId = m_pointPicker->GetPointId();

            if (actor != nullptr && currentPointId != -1 && infomationGraph3DBasicalId != -1)
            {
                if (m_graph3DWindowBase == nullptr)
                {
                    return;
                }
                auto dataSet = m_pointPicker->GetDataSet();
                if (!dataSet)
                {
                    return;
                }
                auto activeArray = dataSet->GetPointData()->GetScalars();
                QString pickedValue = "null";
                QString arrayName = "";
                int fieldIndex = -1;
                if (activeArray != nullptr)//原数据有激活point场
                {
                    if (currentPointId < dataSet->GetNumberOfPoints())
                    {
                        double value = activeArray->GetComponent(currentPointId, 0);
                        pickedValue = QString::number(value);
                        arrayName = activeArray->GetName();

                        auto arraysNum = dataSet->GetPointData()->GetNumberOfArrays();
                        for (int i = 0; i < arraysNum; ++i)
                        {
                            if (dataSet->GetPointData()->GetArray(i)== activeArray)
                            {
                                fieldIndex = i;
                                break;
                            }
                        }
                    }
                    else
                    {
                        qDebug() << "Error:currentPointId is out of range";
                    }
                }

                int windowUniversalID = -1;
                windowUniversalID = m_graph3DWindowBase->getWindowUniversalID();

                QStringList _pyCodes{};
                _pyCodes += QString("postmarkeraddsetting1 = PostProcessing.PostMarkerAddSetting()");
                _pyCodes += QString("postmarkeraddsetting1.setWindowUniversalId(%1)").arg((int)windowUniversalID);
                _pyCodes += QString("postmarkeraddsetting1.setInfomationGraph3DBasicalId(%1)").arg((int)infomationGraph3DBasicalId);
                _pyCodes += QString("postmarkeraddsetting1.setType(%1)").arg((int)0);
                _pyCodes += QString("postmarkeraddsetting1.setFieldIndex(%1)").arg(fieldIndex);
                _pyCodes += QString("postmarkeraddsetting1.setFieldName(\"%1\")").arg(arrayName);
                _pyCodes += QString("postmarkeraddsetting1.setPickedId(%1)").arg((int)currentPointId);
                _pyCodes += QString("postmarkeraddsetting1.setPickedValue(\"%1\")").arg(pickedValue);
                _pyCodes += QString("postmarkeraddsetting1.savePostMarkerAddSettingData()");

                emit IBaseSignalInstance->signal_execPYCode(_pyCodes, true, false);

                m_graph3DWindowBase->addMarkerDataInfo(infomationGraph3DBasicalId, 0, fieldIndex, arrayName, currentPointId, pickedValue, m_moveActor);
            }
        }
        else if (m_pickerType == 1)
        {
            m_cellPicker->Pick(clickPos[0], clickPos[1], 0, this->GetDefaultRenderer());
            auto actor = m_cellPicker->GetActor();
            int infomationGraph3DBasicalId = WindowTotalDataInstance->getInfomationGraph3DBasicalIdByActor(actor);
            auto currentCellId = m_cellPicker->GetCellId();
            //double pickedPosition[3];
            //m_cellPicker->GetPickPosition(pickedPosition);

            if (actor != nullptr && currentCellId != -1 && infomationGraph3DBasicalId != -1)
            {
                if (m_graph3DWindowBase == nullptr)
                {
                    return;
                }
                auto dataSet = m_cellPicker->GetDataSet();
                if (!dataSet)
                {
                    return;
                }
                auto activeArray = dataSet->GetCellData()->GetScalars();
                QString pickedValue = "null";
                QString arrayName = "";
                int fieldIndex = -1;
                if (activeArray != nullptr)//原数据有激活cell场
                {
                    if (currentCellId < dataSet->GetNumberOfCells())
                    {
                        double value = activeArray->GetComponent(currentCellId, 0);
                        pickedValue = QString::number(value);
                        arrayName = activeArray->GetName();

                        auto arraysNum = dataSet->GetCellData()->GetNumberOfArrays();
                        for (int i = 0; i < arraysNum; ++i)
                        {
                            if (dataSet->GetCellData()->GetArray(i)->GetName() == arrayName)
                            {
                                fieldIndex = i;
                                break;
                            }
                        }
                    }
                    else
                    {
                        qDebug() << "Error:currentCellId is out of range";
                    }
                }

                int windowUniversalID = -1;
                windowUniversalID = m_graph3DWindowBase->getWindowUniversalID();

                QStringList _pyCodes{};
                _pyCodes += QString("postmarkeraddsetting2 = PostProcessing.PostMarkerAddSetting()");
                _pyCodes += QString("postmarkeraddsetting2.setWindowUniversalId(%1)").arg((int)windowUniversalID);
                _pyCodes += QString("postmarkeraddsetting2.setInfomationGraph3DBasicalId(%1)").arg((int)infomationGraph3DBasicalId);
                _pyCodes += QString("postmarkeraddsetting2.setType(%1)").arg((int)1);
                _pyCodes += QString("postmarkeraddsetting2.setFieldIndex(%1)").arg(fieldIndex);
                _pyCodes += QString("postmarkeraddsetting2.setFieldName(\"%1\")").arg(arrayName);
                _pyCodes += QString("postmarkeraddsetting2.setPickedId(%1)").arg((int)currentCellId);
                _pyCodes += QString("postmarkeraddsetting2.setPickedValue(\"%1\")").arg(pickedValue);
                _pyCodes += QString("postmarkeraddsetting2.savePostMarkerAddSettingData()");

                emit IBaseSignalInstance->signal_execPYCode(_pyCodes, true, false);

                m_graph3DWindowBase->addMarkerDataInfo(infomationGraph3DBasicalId, 1, fieldIndex, arrayName, currentCellId,
                    pickedValue, edgeActor);
            }
        }
    }

    void PostMarkerInteractionStyle::OnLeftButtonUp()
    {
        if (m_interactionStyle == 0) // 左键按住是旋转
        {
            vtkInteractorStyleTrackballCamera::OnLeftButtonUp();
        }
        else if (m_interactionStyle == 1) // 左键按住是平移
        {
            vtkInteractorStyleTrackballCamera::OnMiddleButtonUp();
        }
    }

    void PostMarkerInteractionStyle::OnRightButtonDown()
    {
        vtkInteractorStyleTrackballCamera::OnRightButtonDown();
        if (!m_isEnablePicking)
        {
            return;
        }
        auto actor = m_cellPicker->GetActor();
        auto currentCellId = m_cellPicker->GetPointId();
        if (actor != nullptr && currentCellId != -1)
        {
            // m_postWindow->rightClickedActorAndPointId(actor, currentCellId);
        }
    }

    void PostMarkerInteractionStyle::OnMouseMove()
    {
        vtkInteractorStyleTrackballCamera::OnMouseMove();
        if (!m_isEnablePicking)
        {
            return;
        }

        int* clickPos = this->GetInteractor()->GetEventPosition();

        if (m_pickerType == 0) // 点拾取
        {
            int success = -1;
            success = m_pointPicker->Pick(clickPos[0], clickPos[1], 0, this->GetDefaultRenderer());
            auto actor = m_pointPicker->GetActor();
            auto currentPointId = m_pointPicker->GetPointId();

            if (actor != nullptr && currentPointId != -1)
            {
                m_moveActor->SetVisibility(true);

                vtkDataSet* dataSet = actor->GetMapper()->GetInput();
                double* point = dataSet->GetPoint(currentPointId);
                m_moveActor->SetPosition(point);
            }
            else
            {
                m_moveActor->SetVisibility(false);
            }
            this->GetDefaultRenderer()->AddActor(m_moveActor);
            this->GetDefaultRenderer()->GetRenderWindow()->Render();
        }
        else if (m_pickerType == 1)
        {
            int success = -1;
            success = m_cellPicker->Pick(clickPos[0], clickPos[1], 0, this->GetDefaultRenderer());

            //auto actors = this->GetDefaultRenderer()->GetActors();
            auto actor = m_cellPicker->GetActor();
            auto currentCellId = m_cellPicker->GetCellId();
            if (actor != nullptr && currentCellId != -1)
            {
                idList->Reset();
                idList->InsertNextId(currentCellId);
                auto dataSet = m_cellPicker->GetDataSet();
                extractCells->SetInputData(dataSet);
                extractCells->SetCellList(idList);
                extractCells->Update();
                featureEdges->Update();
                edgeActor->Modified();
                edgeActor->SetVisibility(true);

                //edgeActor->Print(std::cout);
                // m_moveActor->SetVisibility(true);
                //double* worldPosition = m_cellPicker->GetPickPosition();
                //m_moveActor->SetPosition(worldPosition);
                this->GetDefaultRenderer()->AddActor(edgeActor);
            }
            else
            {
                edgeActor->SetVisibility(false);
            }
        }

        this->GetDefaultRenderer()->GetRenderWindow()->Render();
    }

    void PostMarkerInteractionStyle::OnKeyPress()
    {
        // 获取按下的键值
        std::string key = this->GetInteractor()->GetKeySym();
        if (key == "Escape")
        {
            m_moveActor->SetVisibility(false);
            edgeActor->SetVisibility(false);
            if (m_graph3DWindowBase != nullptr)
            {
                m_graph3DWindowBase->slot_stopAddMarker();
            }
        }
        vtkInteractorStyleTrackballCamera::OnKeyPress();
    }

    // void PostMarkerInteractionStyle::Rotate()
    //{
    // }

} // namespace pst
